﻿//===============================================================================
// Microsoft Innovation Centre - Western Europe
// Copyright (c) 2008 Microsoft Corporation. All rights reserved.
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================
// The example companies, organizations, products, domain names,
// e-mail addresses, logos, people, places, and events depicted
// herein are fictitious.  No association with any real company,
// organization, product, domain name, email address, logo, person,
// places, or events is intended or should be inferred.
//===============================================================================

using System;
using System.ComponentModel;
using System.Net;
using System.ServiceModel;
using System.ServiceModel.Syndication;
using System.Text;
using System.Threading;
using System.Xml;
using Microsoft.WVB.Framework;
using Microsoft.WVB.Silverlight.Infrastructure;

namespace Microsoft.WVB.Services
{
    /// <summary>.
    /// Atlas Ad Manager is a Microsoft Ad Software back-end
    /// An Atlas implementation of the abstract class AdProvider
    /// </summary>
    public class AtlasService : AdProvider
    {
        private SendOrPostCallback onGetAdCompleted = null;
        private const string serviceUri = "http://demo4.adbureau.net/xtserver";
        private const string site = "DPE";
        private const string area = "SILVERLIGHT";
        private string initial = string.Empty;

        public AtlasService()
        {
            InitializeDelegate();
        }

        public AtlasService(string initialPathAndConfiguration)
            : this()
        {
            this.initial = initialPathAndConfiguration;
        }

        private void InitializeDelegate()
        {
            if (onGetAdCompleted == null)
            {
                Action<object> raiseGetAdCompleted = o =>
                {
                    AcquireCompletedEventArgs<AdContext> e = o as AcquireCompletedEventArgs<AdContext>;
                    if (e != null)
                        OnGetAdCompleted(e);
                };
                onGetAdCompleted = new SendOrPostCallback(raiseGetAdCompleted);
            }
        }

        protected override void OnGetAdCompleted(AcquireCompletedEventArgs<AdContext> e)
        {
            base.OnGetAdCompleted(e);
        }

        public override void GetAdAsync(AdProviderContext adProviderContext, object userData)
        {
            // Prepare the reuqest - serialize the information about the context and the profile
            // in order to send it to Atlas ... it has to be in a form of a query with "/" as separator
            Uri adRequest = null;
            WebClient wClient = new WebClient();

            AsyncOperation op = AsyncOperationManager.CreateOperation(ensureUserData(userData));
            AcquireCompletedEventArgs<AdContext> args = null;

            wClient.OpenReadCompleted += delegate(object sender, OpenReadCompletedEventArgs e)
            {
                WVBServiceException ex = null;
                AsyncOperation aop = e.UserState as AsyncOperation;
                AdContext ctx = null;
                Boolean cancelled = false;
#if TRACEDEBUG
                Debug.WriteLine(e.Address);
#endif
                try
                {
                    if ((e.Error == null) && (!e.Cancelled))
                    {
                        ctx = adProviderContext.Context;
                        aop.SynchronizationContext.OperationStarted();
                        XmlReader reader = XmlReader.Create(e.Result);

                        SyndicationFeed feed = SyndicationFeed.Load(reader);
                        EntityConverter.FillAdContext(feed, ctx);
                        ctx.IsProvisioned = true;
                    }
                    else if (e.Error != null)
                    {
                        ex = new WVBServiceException(string.Format(Strings.WCF_Services_Exception_Unknown, "GetAdAsync"), "Unknown", "AtlasService.GetAdAsync", e.Error);

                    }
                    else if (e.Cancelled)
                    {
                        cancelled = true;
                    }
                }
                catch (TimeoutException timeoutException)
                {
                    ex = new WVBServiceException(timeoutException.Message, "TimeoutException", "AtlasService.GetAdAsync", timeoutException);
                }
                catch (FaultException fException)
                {
                    ex = new WVBServiceException(fException.Message, "FaultException", "AtlasService.GetAdAsync", fException);
                }
                catch (CommunicationException comException)
                {
                    ex = new WVBServiceException(comException.Message, "CommunicationException", "AtlasService.GetAdAsync", comException);
                }
                catch (Exception generalException)
                {
                    ex = new WVBServiceException(string.Format(Strings.WCF_Services_Exception_Unknown, "GetAdAsync"), "Unknown", "AtlasService.GetAdAsync", generalException);
                }

                args = new AcquireCompletedEventArgs<AdContext>(ctx, ex, cancelled, aop.UserSuppliedState);
                aop.PostOperationCompleted(onGetAdCompleted, args);
            };

            CreateAtlasRequest(adProviderContext, userData, out adRequest);

            if (adRequest != null)
            {
                wClient.OpenReadAsync(adRequest, op);
            }
            else
            {
                args = new AcquireCompletedEventArgs<AdContext>(null, new NullReferenceException(Strings.WCF_Services_Exception_NullReference), false, op.UserSuppliedState);
                op.PostOperationCompleted(onGetAdCompleted, args);
            }
        }

        private void CreateAtlasRequest(AdProviderContext providerCtx, object userData, out Uri adQueryRequest)
        {
            Random rd = new Random();
            StringBuilder sb = new StringBuilder();

            if (this.initial == String.Empty)
                sb.AppendFormat("{0}/SITE={1}/AREA={2}", serviceUri, site, area);
            else
                sb.Append(this.initial);

            if (providerCtx.Profile != null)
            {
                sb.AppendFormat("/GENDER={0}/COUNTRY={1}/BIRTHYEAR={2}/", providerCtx.Profile.Gender.ToString(),
                    providerCtx.Profile.Country, (providerCtx.Profile.BirthDate.HasValue)?  providerCtx.Profile.BirthDate.Value.Year.ToString(): default(string));
            }

            sb.Append(providerCtx.Context.AdKeywords);

            sb.AppendFormat("/RANDOM={0}", rd.Next(10000, 100000));

            sb.AppendFormat("/PAGEID={0}", IoC.GetCreate<AdManager>().SessionId);
            
            adQueryRequest = new Uri(sb.ToString(), UriKind.Absolute);
        }

        private object ensureUserData(object userData)
        {
            if (userData == null)
            {
                return Guid.NewGuid();
            }
            else
            {
                return userData;
            }
        }
    }
}
